7.4 Redis集群

Redis官方不支持Windows,所以,这一小节我们以macOS操作系统为例,来搭建Redis集群,Linux(如CentOS)下的集群搭建步骤和macOS相同。

本小节参考官方集群搭建文档说明来在本机上搭建三主三从的集群,端口分布为7001-7006。

Redis集群需要至少3个节点,主从复制集群至少需要6个节点。否则会提示如下错误信息:

*** ERROR: Invalid configuration for cluster creation.
*** Redis Cluster requires at least 3 master nodes.
*** This is not possible with 2 nodes and 1 replicas per node.
*** At least 6 nodes are required.

7.4.1 下载安装

官方下载最新的稳定版Redis 5.0.7,将下载的文件redis-5.0.7.tar.gz拷贝到用户目录下。

打开终端,输入tar -zxf redis-5.0.7.tar.gz将其解压到/Users/kevin/redis-5.0.7目录。

进入Redis目录(/Users/kevin/redis-5.0.7)后输入make install编译安装Redis服务器。

你的mac可能会出现xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun错误,可以执行xcode-select --install命令,安装编译依赖环境。

image-20191129232411577

7.4.2 单机配置

我们编译安装完Redis后,建议先配置单机环境,检查Redis服务器是否能正常工作。

为了方便文件分类存放,建议创建配置etc和数据库db目录。

mkdir etc
mkdir db

/Users/kevin/redis-5.0.7/etc/redis-single-7001.conf配置文件中配置Redis参数。

#修改为守护模式
daemonize yes
#设置进程锁文件
pidfile /Users/kevin/redis-5.0.7/db/redis-7001.pid
#ip地址
bind 127.0.0.1
#端口
port 7001
#客户端超时时间
timeout 300
#日志级别
loglevel debug
#日志文件位置
logfile /Users/kevin/redis-5.0.7/logs/redis-7001.log
#设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id
databases 16
##指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
#save <seconds> <changes>
#Redis默认配置文件中提供了三个条件:
save 900 1
save 300 10
save 60 10000
#指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大
rdbcompression yes
#指定本地数据库文件名
dbfilename dump-7001.rdb
#指定本地数据库路径
dir /Users/kevin/redis-5.0.7/db/
#指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中
appendonly no
#指定更新日志条件,共有3个可选值:
#no:表示等操作系统进行数据缓存同步到磁盘(快)
#always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
#everysec:表示每秒同步一次(折衷,默认值)
appendfsync everysec

在命令终端执行如下命令,在7001端口上启动Redis单机服务器。

/Users/kevin/redis-5.0.7/src/redis-server /Users/kevin/redis-5.0.7/etc/redis-single-7001.conf

输入命令ps -ef | grep redis检查Redis是否在7001端口上启动。

kevin@KevindeMacBook-Pro src % ps -ef | grep redis                   
  501  2048     1   0  9:12上午 ??         0:00.84 /Users/kevin/redis-5.0.7/src/redis-server *:7001 
  501  2070   943   0  9:15上午 ttys000    0:00.00 grep redis

在命令终端执行命令redis-cli -h 127.0.0.1 -p 7001,启动Redis客户端,往Redis中添加一条记录并获取,检查是否正确保存和查询记录。

kevin@KevindeMacBook-Pro src % /Users/kevin/redis-5.0.7/src/redis-cli -h 127.0.0.1 -p 7001
127.0.0.1:7001> set name 'Kevin'
OK
127.0.0.1:7001> get name
"Kevin"
127.0.0.1:7001>

7.4.3 集群配置

本测试集群为6台在本地机器上的Redis服务器,只是端口号不同。

redis-single-7001.conf配置文件拷贝为redis-7001.conf,并在文件末尾添加集群配置内容。

#开启集群
cluster-enabled yes
#该节点的对应的节点配置文件
cluster-config-file redis-7001.conf
#集群超时时间
cluster-node-timeout 5000

完整的配置文件如下:

#修改为守护模式
daemonize yes
#设置进程锁文件
pidfile /Users/kevin/redis-5.0.7/db/redis-7001.pid
#ip地址
bind 127.0.0.1
#端口
port 7001
#客户端超时时间
timeout 300
#日志级别
loglevel debug
#日志文件位置
logfile /Users/kevin/redis-5.0.7/logs/redis-7001.log
#设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id
databases 16
##指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
#save <seconds> <changes>
#Redis默认配置文件中提供了三个条件:
save 900 1
save 300 10
save 60 10000
#指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大
rdbcompression yes
#指定本地数据库文件名
dbfilename dump-7001.rdb
#指定本地数据库路径
dir /Users/kevin/redis-5.0.7/db/
#指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中
appendonly no
#指定更新日志条件,共有3个可选值:
#no:表示等操作系统进行数据缓存同步到磁盘(快)
#always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
#everysec:表示每秒同步一次(折衷,默认值)
appendfsync everysec

#开启集群
cluster-enabled yes
#该节点的对应的节点配置文件
cluster-config-file redis-7001.conf
#集群超时时间
cluster-node-timeout 5000

拷贝redis-7001.conf为7002-7006,并修改文件中的所有的7001为对应端口,然后保存。

使用查找替换功能,将redis-7001.conf文件中的所有7001替换为7002,7003...

分别启动7001-7006服务器。

/Users/kevin/redis-5.0.7/src/redis-server /Users/kevin/redis-5.0.7/etc/redis-7001.conf
/Users/kevin/redis-5.0.7/src/redis-server /Users/kevin/redis-5.0.7/etc/redis-7002.conf
/Users/kevin/redis-5.0.7/src/redis-server /Users/kevin/redis-5.0.7/etc/redis-7003.conf
/Users/kevin/redis-5.0.7/src/redis-server /Users/kevin/redis-5.0.7/etc/redis-7004.conf
/Users/kevin/redis-5.0.7/src/redis-server /Users/kevin/redis-5.0.7/etc/redis-7005.conf
/Users/kevin/redis-5.0.7/src/redis-server /Users/kevin/redis-5.0.7/etc/redis-7006.conf

执行ps -ef | grep redis命令,检查六台Redis服务器是否正确启动。

kevin@KevindeMacBook-Pro src % ps -ef | grep redis
  501  2209     1   0 10:14上午 ??         0:01.43 /Users/kevin/redis-5.0.7/src/redis-server 127.0.0.1:7001 [cluster] 
  501  2212     1   0 10:15上午 ??         0:01.35 /Users/kevin/redis-5.0.7/src/redis-server 127.0.0.1:7002 [cluster] 
  501  2229     1   0 10:19上午 ??         0:00.14 /Users/kevin/redis-5.0.7/src/redis-server 127.0.0.1:7003 [cluster] 
  501  2231     1   0 10:19上午 ??         0:00.13 /Users/kevin/redis-5.0.7/src/redis-server 127.0.0.1:7004 [cluster] 
  501  2233     1   0 10:19上午 ??         0:00.10 /Users/kevin/redis-5.0.7/src/redis-server 127.0.0.1:7005 [cluster] 
  501  2235     1   0 10:19上午 ??         0:00.09 /Users/kevin/redis-5.0.7/src/redis-server 127.0.0.1:7006 [cluster] 
  501  2237   943   0 10:20上午 ttys000    0:00.00 grep redis

执行命令redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1创建集群。

/Users/kevin/redis-5.0.7/src/redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1

如果你严格按照本小节的步骤操作,很有可能要报错,错误信息如下:

[ERR] Node 127.0.0.1:7001 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.

原因如上面错误提示“contains some key in database 0”,是因为我们之前的测试数据本地落盘后数据库中有记录了。解决办法是删除/Users/kevin/redis-5.0.7/db目录下的所有文件。

然后再次执行命令redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1创建集群。

image-20191130102800578

输入yes确认信息后,Redis开始创建主从复制集群,耐心等待(时间应该少于2分钟),直到集群创建完成。

image-20191130103521112

使用命令redis-cli -h 127.0.0.1 -p 7003 -c cluster nodes连接到任意集群节点服务器(这里我们连接的是7003端口的那台Redis服务器),检查集群节点情况。

kevin@KevindeMacBook-Pro src % redis-cli -h 127.0.0.1 -p 7003 -c cluster nodes
96566556628bcea7deff9f50cb8b59b77c2fad6b 127.0.0.1:7005@17005 slave acbb54dc08ee4525ee0b978b16c7b1495fe0fc90 0 1575081455088 5 connected
5ed24cb77a7775a9887ceeff19650393b70e08e5 127.0.0.1:7002@17002 master - 0 1575081456099 2 connected 5461-10922
f21ed6f9cce15836d288184d3db363fe7e4b1d71 127.0.0.1:7006@17006 slave 5ed24cb77a7775a9887ceeff19650393b70e08e5 0 1575081455086 6 connected
78d9c15de0020fb110aefe9fc8dad85bffad2e55 127.0.0.1:7004@17004 slave 6a6c66c8863a9718ced1a91d2cb08d5b82da384f 0 1575081454073 4 connected
6a6c66c8863a9718ced1a91d2cb08d5b82da384f 127.0.0.1:7003@17003 myself,master - 0 1575081454000 3 connected 10923-16383
acbb54dc08ee4525ee0b978b16c7b1495fe0fc90 127.0.0.1:7001@17001 master - 0 1575081454000 1 connected 0-5460

使用命令redis-cli --cluster check 127.0.0.1:7002检查集群情况。

kevin@KevindeMacBook-Pro src % redis-cli --cluster check 127.0.0.1:7002
127.0.0.1:7002 (5ed24cb7...) -> 0 keys | 5462 slots | 1 slaves.
127.0.0.1:7003 (6a6c66c8...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:7001 (acbb54dc...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 127.0.0.1:7002)
M: 5ed24cb77a7775a9887ceeff19650393b70e08e5 127.0.0.1:7002
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: 6a6c66c8863a9718ced1a91d2cb08d5b82da384f 127.0.0.1:7003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: f21ed6f9cce15836d288184d3db363fe7e4b1d71 127.0.0.1:7006
   slots: (0 slots) slave
   replicates 5ed24cb77a7775a9887ceeff19650393b70e08e5
M: acbb54dc08ee4525ee0b978b16c7b1495fe0fc90 127.0.0.1:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 78d9c15de0020fb110aefe9fc8dad85bffad2e55 127.0.0.1:7004
   slots: (0 slots) slave
   replicates 6a6c66c8863a9718ced1a91d2cb08d5b82da384f
S: 96566556628bcea7deff9f50cb8b59b77c2fad6b 127.0.0.1:7005
   slots: (0 slots) slave
   replicates acbb54dc08ee4525ee0b978b16c7b1495fe0fc90
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

7.4.4 集群测试

使用命令redis-cli -c -h 127.0.0.1 -p 7002启动Redis客户端,连接到集群中的7002服务器,往Redis集群中添加一条记录并获取,检查是否正确保存和查询记录。

kevin@KevindeMacBook-Pro src % redis-cli -c -h 127.0.0.1 -p 7002
127.0.0.1:7002> set name 'Kevin'
OK
127.0.0.1:7002> get name
"Kevin"
127.0.0.1:7002>

退出连接7002服务器的Redis客户端。使用命令redis-cli -c -h 127.0.0.1 -p 7005启动Redis客户端,连接到集群中的7005服务器,在Redis集群中获取刚才通过7002服务器添加的name=Kevin的那条记录。

kevin@KevindeMacBook-Pro src % redis-cli -c -h 127.0.0.1 -p 7005
127.0.0.1:7005> get name
-> Redirected to slot [5798] located at 127.0.0.1:7002
"Kevin"
127.0.0.1:7002>

经检查,集群可以正常工作。

如果是生产环境下的Redis集群,不要忘了使用redis-benchmark -h 127.0.0.1 -p 7006 -c 100 -n 10000命令检查服务器性能。

100个并发连接,10000个请求,检测host为127.0.0.1端口为7006的redis服务器性能

image-20191130110015034

如上图所示,在我的MacBook Pro(i5+8G内存)笔记本上,每秒能处理7万多个请求,超过98%的请求响应时间少于2毫秒。

7.4.5 Spring Boot使用Redis集群

Spring Boot 1.x系列中,访问Redis使用的客户端是Jedis,但是到了Spring Boot 2.x使用的客户端是Lettuce。 关于JedisLettuce的区别如下:

  • Lettuce 和 Jedis 的定位都是Redis的Client,所以他们都可以直接连接Redis Server。
  • Jedis在实现上是直接连接的Redis Server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接。
  • Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,因为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。

所以,在Spring Boot 2.x中使用Redis集群,建议最好使用Lettuce连接Redis集群服务器。

在Spring Boot中访问单机Redis服务器和集群服务器,差别在于配置,最终代码都是使用StringRedisTemplate(或RedisTemplate)模板类来操作Redis数据。

在配置文件application.yml中添加Redis集群配置。

server:
  port: 8080
spring:
  redis:
    timeout: 6000ms
    cluster:
      max-redirects: 3
      nodes:
        - 127.0.0.1:7001
        - 127.0.0.1:7002
        - 127.0.0.1:7003
        - 127.0.0.1:7004
        - 127.0.0.1:7005
        - 127.0.0.1:7006

编写RedisController控制器类,测试访问和保存Redis集群服务器中值对记录。

package com.example.redis.controller;

import javax.annotation.Resource;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/redis/cluster")
public class RedisController {

    @Resource
    private StringRedisTemplate strTemplate;    

    @RequestMapping("/save")
    public String save(String key, String value) {
        strTemplate.opsForValue().set(key, value);
        return "success.";
    }

    @RequestMapping("/get")
    public String get(String key) {
        String value = strTemplate.opsForValue().get(key);
        return value;
    }

}

在浏览器中访问http://localhost:8080/redis/cluster/get?key=name这个地址,访问之前集群测试中放入到Redis集群中的name这个key对应的值。

image-20191130142556998

在浏览器中访问http://localhost:8080/redis/cluster/save?key=age&value=18这个地址,将age=18这个Key-Value值对存入Redis集群中。

image-20191130141913145

在浏览器中访问http://localhost:8080/redis/cluster/get?key=age这个地址,访问Redis集群服务器中的age这个key对应的值。

image-20191130142644625

在命令终端中,连接到Redis集群的7005服务器,查询name和age,可以看到name存放在7002服务器的slot中,age存放在7001服务器的slot中。

kevin@KevindeMacBook-Pro src % redis-cli -c -h 127.0.0.1 -p 7005
127.0.0.1:7005> get name
-> Redirected to slot [5798] located at 127.0.0.1:7002
"Kevin"
127.0.0.1:7002> get age
-> Redirected to slot [741] located at 127.0.0.1:7001
"18"

通过redis-cli --cluster check 127.0.0.1:7002命令再次检查集群服务器,能够看到[OK] 2 keys in 3 masters.信息,就是我们上面通过命令存入Redis集群的name和通过Spring Boot应用存入的age这两条记录了。

kevin@KevindeMacBook-Pro src % redis-cli --cluster check 127.0.0.1:7002
127.0.0.1:7002 (5ed24cb7...) -> 1 keys | 5462 slots | 1 slaves.
127.0.0.1:7003 (6a6c66c8...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:7001 (acbb54dc...) -> 1 keys | 5461 slots | 1 slaves.
[OK] 2 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 127.0.0.1:7002)
M: 5ed24cb77a7775a9887ceeff19650393b70e08e5 127.0.0.1:7002
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: 6a6c66c8863a9718ced1a91d2cb08d5b82da384f 127.0.0.1:7003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: f21ed6f9cce15836d288184d3db363fe7e4b1d71 127.0.0.1:7006
   slots: (0 slots) slave
   replicates 5ed24cb77a7775a9887ceeff19650393b70e08e5
M: acbb54dc08ee4525ee0b978b16c7b1495fe0fc90 127.0.0.1:7001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 78d9c15de0020fb110aefe9fc8dad85bffad2e55 127.0.0.1:7004
   slots: (0 slots) slave
   replicates 6a6c66c8863a9718ced1a91d2cb08d5b82da384f
S: 96566556628bcea7deff9f50cb8b59b77c2fad6b 127.0.0.1:7005
   slots: (0 slots) slave
   replicates acbb54dc08ee4525ee0b978b16c7b1495fe0fc90
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

本小节示例项目代码:

https://github.com/gyzhang/SpringBootCourseCode/tree/master/spring-boot-redis

results matching ""

    No results matching ""